package info.himanshug.www.imageprocessing;

import info.himanshug.www.picfun.Constants;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.Log;

public class PencilSketchEffect {

	private Bitmap originalBitmap;
	private Bitmap scaledBitmap; //Reduce the image size for online processing if needed
	private Bitmap grayScaledBitmap;
	private Bitmap invertedBitmap;
	
	private int lastRadius;
	public static final int DEFAULT_RADIUS = 4;
	
	private int canvasW;
	private int canvasH;
	
	public PencilSketchEffect(Bitmap in, int canvasW, int canvasH) {
		this.canvasH = canvasH;
		this.canvasW = canvasW;
		
		originalBitmap = in;
		scaledBitmap = rescale(in);
		lastRadius = DEFAULT_RADIUS;
	}
	
	private Bitmap rescale(Bitmap in) {
//		return in;
		Log.d(Constants.APP_NAME,"Rescale: Canvas width = " + this.canvasW);
		Log.d(Constants.APP_NAME,"Rescale: Canvas height = " + this.canvasH);
		
		int targetMax = Math.min(Math.min(canvasH, canvasW),500);
		
		int w = in.getWidth();
		int h = in.getHeight();
		
		if(w <= targetMax && h <= targetMax) {
			return in;
		}
		else {
			if(w > h) {
				int newW = targetMax;
				int newH = (int)((float)targetMax * h)/w;
				Log.d(Constants.APP_NAME, "newW = " + newW + " , newH = " + newH);
				return Bitmap.createScaledBitmap(in, newW, newH, true);
			}
			else {
				int newH = targetMax;
				int newW = (int)((float)targetMax * w)/h;
				Log.d(Constants.APP_NAME, "newW = " + newW + " , newH = " + newH);
				return Bitmap.createScaledBitmap(in, newW, newH, true);
			}
		}
	}
	
	
	public Bitmap getSketchBitmap(int radius) {
		long originalStart = System.currentTimeMillis();
		Log.d(Constants.APP_NAME,"applying sketch effect.....1");
		if(radius < 0)
			radius = 0;
		else if(radius > 100)
			radius = 100;
		
		lastRadius = radius;
		Log.d(Constants.APP_NAME,"applying sketch effect..2");
		
//		ImageFilter toGauss = new GaussianImageFilter(16.0f);
		ImageFilter toGauss = new BoxBlurImageFilter((float)radius,(float)radius,2);
		Log.d(Constants.APP_NAME,"applying sketch effect...3");
		ColorDodgeComposite composite = new ColorDodgeComposite(1.0f);
		Log.d(Constants.APP_NAME,"applying sketch effect...5");
		
		if(invertedBitmap == null) {
			Log.d(Constants.APP_NAME,"applying sketch effect...5");
			ImageFilter toGray = new GrayScaleImageFilter();
			ImageFilter toInvert = new InvertColorsImageFilter();
			Log.d(Constants.APP_NAME,"applying sketch effect...6");
			
			grayScaledBitmap = toGray.filter(scaledBitmap);
			invertedBitmap = toInvert.filter(grayScaledBitmap);
			Log.d(Constants.APP_NAME,"applying sketch effect...7");
			
			
			//blur
			long start = System.currentTimeMillis();
			Bitmap blurred = toGauss.filter(invertedBitmap);
//			Bitmap blurred = blur(invertedBitmap,radius);
			Log.d(Constants.APP_NAME,"applying sketch effect...8");
			Log.d(Constants.APP_NAME,"======================= BLUR TIME=======================");
			long finish = System.currentTimeMillis();
			Log.d(Constants.APP_NAME,"Blur time taken = " + (finish - start));
			
			Bitmap result = composite.compose(blurred, grayScaledBitmap);
			Log.d(Constants.APP_NAME,"Total sketch creation time taken = " + (System.currentTimeMillis() - originalStart));
			return result;
//			return blurred;
			
//			ImageFilter toGray = new GrayScaleImageFilter();
//			Bitmap in2 = toGray.filter(in);
//			return in2;
		}
		else {
			//blur
			long start = System.currentTimeMillis();
			Bitmap blurred = toGauss.filter(invertedBitmap);
			Log.d(Constants.APP_NAME,"applying sketch effect...9");
//			Bitmap blurred = blur(invertedBitmap,radius);
			long finish = System.currentTimeMillis();
			Log.d(Constants.APP_NAME,"Blur time taken = " + (finish - start));
			
			Bitmap result = composite.compose(blurred, grayScaledBitmap);
			Log.d(Constants.APP_NAME,"Total sketch creation time taken = " + (System.currentTimeMillis() - originalStart));
			return result;
			//return blurred;
		}
	}
	
	public Bitmap getSketchBitmapFromOriginal() {
		ImageFilter toGray = new GrayScaleImageFilter();
		ImageFilter toInvert = new InvertColorsImageFilter();
		BoxBlurImageFilter toGauss = new BoxBlurImageFilter((float)lastRadius,(float)lastRadius,2);
		ColorDodgeComposite composite = new ColorDodgeComposite(1.0f);
		
		Log.d(Constants.APP_NAME,"grayscaling the original image...");
		Bitmap grayed = toGray.filter(originalBitmap);
		Log.d(Constants.APP_NAME,"inverting the grayscale image...");
		Bitmap invertedAndBlurred = toInvert.filter(grayed);
		Log.d(Constants.APP_NAME,"applying blur...");
//		invertedAndBlurred = blur(invertedAndBlurred,lastRadius);
		invertedAndBlurred = toGauss.filter(invertedAndBlurred,invertedAndBlurred);
		Log.d(Constants.APP_NAME,"merge layers...");
		Bitmap result = composite.compose(invertedAndBlurred, grayed, invertedAndBlurred);
		Log.d(Constants.APP_NAME,"merged layers...");
		return result;
	}
	
	private Bitmap blur(Bitmap src, float radius) {
		Log.d(Constants.APP_NAME,"applying blur...1");
		BlurMaskFilter blurMaskFilter = new BlurMaskFilter(radius, BlurMaskFilter.Blur.INNER);
		Log.d(Constants.APP_NAME,"applying blur...2");
		Paint paint = new Paint();
		paint.setMaskFilter(blurMaskFilter);
		paint.setColor(0xffffffff);
		Log.d(Constants.APP_NAME,"applying blur...3");
		
		src = src.copy(Config.ARGB_8888, true);
		Bitmap blurringLayer = src.extractAlpha(paint, new int[]{0,0});
		blurringLayer = blurringLayer.copy(Config.ARGB_8888, true);
		Log.d(Constants.APP_NAME,"applying blur...4");
		Canvas canvas = new Canvas(blurringLayer);
		Log.d(Constants.APP_NAME,"applying blur...5");
		canvas.drawBitmap(src, 0, 0, null);
		Log.d(Constants.APP_NAME,"applying blur...6");
		return src;
	}
}
